Living in the Materials World: The Lollipop UI

Blake Meike

Blake Meike G. Blake Meike

About me

Developer, Architect, Android Evangelist

Blake

blake.meike@gmail.com

twitter: @callmeike

blog: http://portabledroid.wordpress.com/

About this workshop

Introducing Materials

Material Design

Materials: the Environment

Environment

Materials: Properties

Properties

Materials: Interaction

Interaction

Materials: Elevation

Elevation

Materials: Animation

Animation

Materials: Response

Response

Materials: Color

Color

Materials: Typography

Typography

Materials: The Toolbar

Toolbar

Using Materials

Let’s write some code!

The goal for the rest of this workshop is to port a small Jellybean application to use Material Design.

Porting strategy

There are many ways to port a program.

Using the compatibility library, many Material features can be back ported to previous version of Android.

In this workshop, we will not attempt back-porting: The application will be Holo, pre-Lollipop and Materials on Lollipop.

Step #1: Basic port

As the first step in the port, let’s verify the development environment and enable basic Materials support.

Workspace setup

  1. Download the APIs

  2. Set up an Emulator

  3. Other handy things

    1. Verify that HAXM mem bigger than emulator mem

    2. Before starting the emulator, edit: hw.keyboard=no

    3. CLI alias that kills and restarts the emulator

Yamba 5

  1. Clone Yamba 5, eclipse or Studio

    1. Studio: https://github.com/bmeike/Yamba5Studio.git

    2. Eclipse: https://github.com/bmeike/Yamba5Eclipse.git

  2. Build it

  3. Run it on your emulator

Materializing Yamba

  1. Set targetSdkVersion = 21

  2. Add the v7:21 support library

    compile 'com.android.support:appcompat-v7:21.0.0'
  3. Define elevation policy

  4. Choose primary, primary dark and accent colors

  5. Correct style definitions

Use the -v21 resource qualifier where appropriate!

Step #2: Card View

Next, let’s convert the Tweet View to look more Materialistic:

A card view with a floating button.

Basic layout

  1. Use a FrameLayout to float the button (note, float the button to the top right, so that it doesn’t get covered by the keyboard)

  2. Elevation (mid) the edit text

    • note that, in the current implementation, cards don’t elevate
  3. Test it

  4. Fix the landscape layout

    • Suggest using a relief in the activity layout to leave a larger gutter on -land-v21

Materialize the button

  1. Make an image button (android:ic_input_add)

  2. Fix the size

  3. Correct margins to move it to the right place

  4. Give it some elevation (mid)

  5. Fix the color (android:tint)

  6. Fix the shadow by giving it a background (use an oval shape resource)

  7. Tune the image size (size, padding, filltype = scaleCenter)

Animate it!

Handling enable/disable

The button should be disabled, when the text box does not contain a legal tweet.

Let’s Animate that, too!

Materialize the button!

  1. Set the button invisible in the layout

  2. In the code:

    1. Get the button diameter (it should be set from a resource)

    2. Set the button visible.

    3. Animate! (ViewAnimationUtils.createCircularReveal)

Choreography

That little something extra: a slight delay before the button disappears

Delayed disappear

  1. Add a Handler

  2. Send a delayed message to the Handler, to hide the button

Ooops!

The code now has a fairly serious bug…

Never forget the lifecycle!

  1. Add an OnAttachStateChangeListener to the button

  2. Only animate an attached (non-null) button.

Step #3: Recycler View

The RecyclerView abstracts the implementation of the ListView

Let’s review…

The AdapterView

No doubt, you have coded a ListView

Adapter view

AdapterView implementation

Inflating views is expensive.

The ListView recycles old views, simply replacing content

AdapterView implementation

The View Holder pattern

findViewById can be expensive too…

Using the ViewHolder pattern reduces this expense

ViewHolder

Adapter View problems

Bring on the Recycler View

The Recycler View addresses many of these problems by separating recycler implementation from view layout, and the data adapter.

Introducing the RecyclerView

RecyclerView

Building a RecyclerView.Adapter

  1. Implement a ViewHolder: probably an internal class

  2. Implement, at least, the Adapter’s three abstract methods:

    1. getItemCount

    2. onCreateViewHolder

    3. onBindViewHolder

An Example: SimpleCursorRecyclerViewAdapter

An analog of SimpleCursorAdapter, for the RecyclerView

Check out how easy it is to handle clicks!

SimpleCursorRecyclerViewAdapter

Using a RecyclerView.Adapter

  1. Add the support library (compile 'com.android.support:recyclerview-v7:+\')

  2. Add the RecyclerView to a layout (android.support.v7.widget.RecyclerView)

  3. From the code:

    1. Get a handle to the RecyclerView

    2. Set the layout manager

    3. Set the adapter

Adding the SimpleCursorRecyclerViewAdapter to Yamba

  1. Download the SimpleCursorRecyclerViewAdapter here: http://bit.ly/1wTfLKh

  2. Add the support library (compile com.android.support:recyclerview-v7:+)

  3. Create a new Fragment, LollypopTimelineFragment

    1. Copy TimelineFragment

    2. Replace explicit fragments in layout, with FrameLayout

      • Be sure to fix both layouts!
    3. From the activity, use the new fragment only if Lollypop

  4. Create a layout for the new fragment, containing an android.support.v7.widget.RecyclerView

    • Note that the old fragment, a ListFragment, didn’t have a layout
  5. From the code, find and setup the RecyclerView

    1. Use a LinearLayoutManager

      • Set hasFixedSize, an optimization when all views are the same size
    2. Use a new instance of the SimpleCursorRecyclerViewAdapter i.. Set the adapter ViewBinder ii.. Set the adapter ItemClickListener

  6. Stretch: make the rows card views

Step #4: Transition animation

Use animation to show your user which elements are related

Introducing Shared Element Transitions

Consider the detail view:

Notice that it displays essentially the same information that is shown in the list item.

The transition from the list view, to the detail view, however, completely obscures that fact.

A perfect candidate for shared element transition animation

Shared element?

A shared element is a view (or set of views) that display the same content, in a new context.

Setting up a transition

  1. Define a transition (a resource)

  2. Enable it (a style)

  3. Bind views to transition names the startActivity call (code)

Defining the animation

There are a couple of built in transitions: fade, slide, explode.

Explore! Write new ones!

Transition

Enabling shared element Transitions

Transitions are part of the Activity style. The current style must enable transition:

<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>

... and then name it:

<item name="android:windowSharedElementEnterTransition">
    @transition/transform_tweet_detail
</item>

Transition Names

Transition names are how views at the start of the transition are bound to the views at the end of the transition.

Pair.create(tweetView, "tweet")

works with:

<TextView
    android:id="@+id/timeline_detail_tweet"
    android:transitionName="tweet"

It will animate the view tweetView to the new view R.id.timeline_detail_tweet.

Starting a Transition

There is a new startActivity call:

startActivity(intent, bundle)

where the bundle contains the the transition animation.

ActivityOptions.makeSceneTransitionAnimation

Adding a transition animation to Yamba

  1. Define the animation (a transition set with a single changeBounds)

    • Material design recommends the accelerate_decelerate interpolator
  2. Enable and name the transition, in the application style

  3. In the detail layout, add transitionNames, one per animated value (there are 3)

  4. Modify the ItemClickListener interface, to pass the clicked view

  5. In onItemClicked, bind views to transitionTargets

    1. Use ActivityOptions.makeSceneTransitionAnimation

    2. Use findViewById to find sub view of the passed row, to bind

  6. Use the new version of startActivity to start the Animation

    • Remember that Fragment.startActivity just calls Activity.startActivityFromFragment!!
  7. Stretch: Make the Detail Activity into a materialistic card

    • Remember landscape!

Conclusion

You now have working code for several essential features of Lollipop:

In addition, you have a handy re-implementation of SimpleCursorAdapter, for use with the RecyclerView

And you built it yourself!

Thank you!

The slides and all of the code are available on GitHub:

https://github.com/bmeike/Yamba5Studio

blake.meike@gmail.com

twitter: @callmeike

blog: http://portabledroid.wordpress.com/

Watch for Addison Wesley’s Android Concurrency, Summer 2015

Blake

/

#